package com.zhanghao.ems.sheet;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;

import com.lowagie.text.Document;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStream;
import com.lowagie.text.pdf.PdfWriter;
import com.zhanghao.ems.entity.EMS;
import com.zhanghao.ems.utils.PDFUtils;

public class EMSBuilder {

    /**
     * @param ems
     * @return
     * @throws Exception
     * @desc 根据EMS信息生成PDF打印单
     */
    public PDDocument buildPDF(EMS ems) throws Exception {
        InputStream in = EMSBuilder.class.getClassLoader().getResourceAsStream("EmsSheet.pdf");
        // PDDocument pdf = PDDocument.load(in);
        PDDocument pdf = Loader.loadPDF(in);
        // TrueTypeFont ttf = new
        // TTFParser().parse(EMSBuilder.class.getClassLoader().getResource("simhei.ttf").getPath());
        // PDFont font = PDType0Font.load(pdf, ttf, true);
        PDFont font = PDType0Font.load(pdf, EMSBuilder.class.getClassLoader()
                .getResourceAsStream("simhei.ttf"), true);

        // PDFont font = PDTrueTypeFont.load(pdf,
        // EMSBuilder.class.getClassLoader().getResourceAsStream("simhei.ttf"),
        // Encoding.getInstance(COSName.IDENTITY_H));

        PDResources resources = new PDResources();
        // System.out.println(font.getName());
        resources.put(COSName.getPDFName(font.getName()), font);
        PDDocumentCatalog docCatalog = pdf.getDocumentCatalog();
        PDAcroForm acroForm = docCatalog.getAcroForm();

        acroForm.setDefaultResources(resources);/// simhei 12 Tf 0 0 1 rg

        // fillFields(acroForm, ems);
        drawText(pdf, ems);

        // 条形码信息
        PDTextField barCode = (PDTextField) acroForm.getField("barCode");
        PDRectangle rect = PDFUtils.getPDRectangleForField(barCode);

        PDImageXObject pdImage = PDImageXObject.createFromByteArray(pdf,
                PDFUtils.generateBarCode(ems.getWaybillNO()), ems.getWaybillNO());
        PDPage page = pdf.getPage(0);

        PDPageContentStream pdPageContentStream = new PDPageContentStream(pdf, page,
                PDPageContentStream.AppendMode.APPEND, true, true);
        pdPageContentStream.drawImage(pdImage, rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(),
                rect.getHeight());

        pdPageContentStream.close();
        acroForm.refreshAppearances();
        acroForm.flatten();
        // clearForm(acroForm);
        // ttf.close();
        return pdf;
    }

    /**
     * 根据邮寄信息，直接绘写文字
     * 
     * @param pdf
     * @param ems
     */
    private void drawText(PDDocument pdf, EMS ems) throws IOException {
        PDPage page = pdf.getPage(0);
        PDPageContentStream contentStream = new PDPageContentStream(pdf, page,
                PDPageContentStream.AppendMode.APPEND, true, true);
        PDDocumentCatalog docCatalog = pdf.getDocumentCatalog();
        PDAcroForm acroForm = docCatalog.getAcroForm();

        PDFont font = PDType0Font.load(pdf, EMSBuilder.class.getClassLoader()
                .getResourceAsStream("simhei.ttf"), true);
        // 收件人信息
        PDTextField receiver = (PDTextField) acroForm.getField("receiver");
        PDRectangle receiverRect = PDFUtils.getPDRectangleForField(receiver);

        PDFUtils.addMultipleLines(pdf, ems.getReceiver(), font,
                10, receiverRect, null);

        // 快递单号
        PDTextField waybillNO = (PDTextField) acroForm.getField("waybillNO");
        PDRectangle waybillNORect = PDFUtils.getPDRectangleForField(waybillNO);
        String billNO = ems.getWaybillNO();
        String code = "";
        if (billNO != null) {
            String[] split = billNO.split("");
            for (String str : split) {
                code += str + " ";
            }
        }

        PDFUtils.addMultipleLines(pdf, code, font, 6, waybillNORect, "center");

        // 寄件人信息
        PDTextField sender = (PDTextField) acroForm.getField("sender");
        // sender.getCOSObject().setString(COSName.DA, "/SimHei 6 Tf 0 0 0 rg");
        // addMultipleLines(pdf,ems.getSender(),font,6,PDFUtils.getPDRectangleForField(sender));
        PDFUtils.addMultipleLines(pdf, ems.getSender(), font, 6,
                PDFUtils.getPDRectangleForField(sender), "left");

        // routecode 格口码
        PDTextField routecode = (PDTextField) acroForm.getField("routecode");
        // routecode.getCOSObject().setString(COSName.DA, "/SimHei 10 Tf 0 0 0 rg");
        PDFUtils.addMultipleLines(pdf, ems.getRoutecode(), font, 10, PDFUtils.getPDRectangleForField(routecode),
                null);

        // company公司名称
        PDTextField company = (PDTextField) acroForm.getField("company");
        // company.getCOSObject().setString(COSName.DA, "/SimHei 6 Tf 0 0 0 rg");
        PDFUtils.addMultipleLines(pdf, ems.getCompany(), font, 6, PDFUtils.getPDRectangleForField(company),
                null);

        // comments 备注
        PDTextField comments = (PDTextField) acroForm.getField("comments");
        // comments.getCOSObject().setString(COSName.DA, "/SimHei 6 Tf 0 0 0 rg");
        PDFUtils.addMultipleLines(pdf, ems.getComments(), font, 6, PDFUtils.getPDRectangleForField(comments),
                null);
        // 打印日期
        PDTextField printTime = (PDTextField) acroForm.getField("printTime");
        PDFUtils.addMultipleLines(pdf, ems.getPrintTime(), font, 5, PDFUtils.getPDRectangleForField(printTime),
                null);

        contentStream.close();

    }

    /**
     * 将图片转换为pdf格式
     * 
     * @param image 需要转换的图片
     * @return PDDocument 转换后生成的pdf文件
     * @throws IOException
     */
    private PDDocument image2Pdf(BufferedImage image) throws IOException {

        PDDocument document = new PDDocument();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "png", outputStream);
        // ByteArrayInputStream in = new
        // ByteArrayInputStream(outputStream.toByteArray());
        float width = 215.4f;
        float height = 365.64f;
        PDPage page = new PDPage(new PDRectangle(width, height));
        document.addPage(page);

        PDImageXObject img = PDImageXObject.createFromByteArray(document, outputStream.toByteArray(), "image");
        PDPageContentStream contentStream = new PDPageContentStream(document, page,
                PDPageContentStream.AppendMode.APPEND, true, true);
        contentStream.drawImage(img, 0, 0, width, height);
        contentStream.close();
        return document;
    }

    /**
     * 根据EMS实体数据信息,生成PDF格式EMS打印单据
     * 
     * @param EMS
     * @return PDDocument 生成的pdf格式文件
     * @throws Exception
     */
    public PDDocument buildImagePDF(EMS ems) throws Exception {
        PDDocument pdDocument = this.buildPDF(ems);
        BufferedImage image = PDFUtils.convertPdf2Image(pdDocument, 300);
        PDDocument document = this.image2Pdf(image);
        return document;
    }

    /**
     * 将pdf内容转换为图片格式
     * 
     * @param emsList
     * @return
     * @throws Exception
     */
    public PDDocument buildImagePDF(List<EMS> emsList) throws Exception {
        if (emsList == null) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PDFMergerUtility pdfMerger = new PDFMergerUtility();
        pdfMerger.setDestinationStream(out);

        for (EMS ems : emsList) {
            PDDocument pdDocument = buildImagePDF(ems);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            pdDocument.save(outputStream);
            pdDocument.close();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            pdfMerger.addSource(inputStream);
        }
        pdfMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
        // PDDocument pdf = PDDocument.load(new
        // ByteArrayInputStream(out.toByteArray()));
        PDDocument pdf = Loader.loadPDF(new ByteArrayInputStream(out.toByteArray()));
        return pdf;
    }

    /**
     * 批量将EMS 合并到一个PDF中.
     * 
     * @param emsList EMS实体类列表
     * @param target  生成后PDf对应的OutputStrem 输出流
     * @throws Exception
     */
    public void buildPDF(List<EMS> emsList, OutputStream target) throws Exception {

        if (emsList == null || target == null) {
            return;
        }

        // 用openpdf 创建一个pdf文件用于合并通知书
        Document document = new Document();
        PdfCopy writer = new PdfCopy(document, new BufferedOutputStream(target));
        writer.setPdfVersion(PdfWriter.VERSION_1_7);
        writer.setFullCompression();
        writer.setCompressionLevel(PdfStream.BEST_COMPRESSION);
        document.open();

        for (int i = 0; i < emsList.size(); i++) {
            EMS ems = emsList.get(i);
            PDDocument pdDocument = buildPDF(ems);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            pdDocument.save(outputStream);
            pdDocument.close();

            // we create a reader for a certain document
            PdfReader reader = new PdfReader(new BufferedInputStream(
                    new ByteArrayInputStream(outputStream.toByteArray())));
            reader.consolidateNamedDestinations();
            // we retrieve the total number of pages
            int numberOfPages = reader.getNumberOfPages();

            // we add content 合并pdf文档
            PdfImportedPage page;
            for (int j = 1; j <= numberOfPages; j++) {
                page = writer.getImportedPage(reader, j);
                writer.addPage(page);
            }
            writer.freeReader(reader);
        }

        document.close();

    }

}
